#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     __init__.py
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/12/22
-------------------------------------------------
   修改描述-2021/12/22:  参考信号库自己仿写的一个事件处理机制，
-------------------------------------------------

"""

from collections import defaultdict
import inspect
import functools
# from azyxfastcore.core_libs.transf_sync_aysnc.sync_to_async import threadpool_run_in_executor
from zyxfastutils.libs.transf_sync_aysnc.sync_to_async import threadpool_run_in_executor


def hashable_identity(obj):
    if hasattr(obj, '__func__'):
        return (id(obj.__func__), id(obj.__self__))
    elif hasattr(obj, 'im_func'):
        return (id(obj.im_func), id(obj.im_self))
    elif isinstance(obj, str):
        return obj
    else:
        return id(obj)


class Event:
    pass

    def __init__(self):
        # 定义所有的注册事件对象信息，使用一个字典来保存，对应的事件的ID和事件注册的函数或对象-所有的订阅对象
        self.receivers_subscribes = {}
        # 保持的是注册的对象事件源ID 和 接受者对象的名称
        self._by_receiver = defaultdict(set)  # 创建集合set---默认的是一个字典，当找不到对应的key返回的一个set类型的对象，而不是会报空
        # 保存的是所有的发送者（类似主题类型的分配）
        self._by_sender = defaultdict(set)  # 对应的一个发送者所有的书画报

    def register_subscribe(self, receiver, sender='ZYXEvent'):
        '''
         开始创建一个方法，用于把订阅对象信息进行存贮并根据相关的发生事件的名称和主题等分类
         ：PS:一个事件可以有多个主题，或多个发送至，可以根据主题和发送者过滤相关的处理
        :param receiver: 注册对象（订阅者函数或类或其他）
        :param sender: 发送者（或发送主题名称）
        :return:
        '''
        pass
        # 创建一个注册对象的唯一的ID索引，用户标记定义这的唯一信息
        # 生成订阅者对象ID
        receiver_id = hashable_identity(receiver)
        # 生成发送者的ID
        sender_id = hashable_identity(sender)
        # 把订阅者保持到字典里面进行存贮
        self.receivers_subscribes.setdefault(receiver_id, receiver)
        # 删除当前注册的订阅者，减少引用
        # 记录不同的发送者对应的多个的发送者的ID信息：{'sdfsdf': {'nihao1', 'nihao3', 'nihao2'}, 'sdfsdf2': {'nihao3'}})
        # 一个发送者可以对应多个注册者的信息
        self._by_sender[sender_id].add(receiver_id)
        # 记录每订阅者对象ID，内都有哪些发送者的ID信息---用于过滤且当且只有存在这个发送者信息的时候，才会进行事件回调处理
        self._by_receiver[receiver_id].add(sender_id)
        # 范湖idangq的注册者信息
        return receiver

    def register_subscribe_decorator(self, sender):
        '''
        有惨的时候，需要传参，不能使用默认值，且需要此装饰器
        :param sender:
        :return:
        '''

        def decorator(fn):
            self.register_subscribe(fn, sender)
            return fn

        return decorator

    async def send_async(self, sender='ZYXEvent', **kwargs):
        if not self.receivers_subscribes:
            return []
        else:
            for receiver in self.receivers_for(sender):
                if inspect.iscoroutinefunction(receiver):
                    # 添加的协程的列表里面用户后续的批量的执行
                    #将协程转成task，并组成list
                    # print("应该是协程啊！！！",asyncio.create_task(receiver))
                    # iscoroutinefunctions.append(receiver)
                    await receiver(sender, **kwargs)
                else:
                    # 把同步的阻塞的任务或函数的执行，转为异步可以等待的协程的任务
                    # 但是本质主要作用不是把同步变成协程运行，而是让其拥有了异步await 的用法，
                    # 既能不阻塞当前事件循环，又能在同步函数执行完成return结果时拿到结果接着用
                    # loop = asyncio.get_event_loop()
                    # threadpool_executor = None or global_threadpool_executor
                    # await loop.run_in_executor(executor=threadpool_executor,func=functools.partial(receiver, sender, **kwargs))
                    await threadpool_run_in_executor(func=functools.partial(receiver, sender, **kwargs))


    def send_sync(self, sender='ZYXEvent', **kwargs):

        if not self.receivers_subscribes:
            return []
        else:
            return [receiver(sender, **kwargs) for receiver in self.receivers_for(sender)]

    def receivers_for(self, sender):
        """Iterate all live receivers listening for *sender*."""
        pass
        if self.receivers_subscribes:
            pass
            # 根据发送者ID--获取对应的对应多个注册者的信息ids
            sender_id = hashable_identity(sender)
            # 根据发生者ID来 获取相关的订阅者的IDS信息
            receiver_ids = (self._by_sender[sender_id])
            if not receiver_ids:
                return

            for receiver_id in receiver_ids:
                receiver = self.receivers_subscribes.get(receiver_id)
                if receiver is None:
                    continue
                yield receiver

    def has_receivers_for(self, sender):

        if not self.receivers_subscribes:
            return False
        if self._by_sender[sender]:
            return True
        return hashable_identity(sender) in self._by_sender


class NamedEvent(Event):
    """A named generic notification emitter."""

    def __init__(self, name, ):
        Event.__init__(self)

        #: The name of this signal.
        self.name = name

    def __repr__(self):
        base = Event.__repr__(self)
        return "%s; %r>" % (base[:-1], self.name)


class NameEventspace(dict):
    """A mapping of signal names to signals."""

    def event(self, name):
        """Return the :class:`NamedSignal` *name*, creating it if required.
        Repeated calls to this function will return the same signal object.
        """
        try:
            return self[name]
        except KeyError:
            return self.setdefault(name, NamedEvent(name))

    def has_receiver(self, name):
        """Return the :class:`NamedSignal` *name*, creating it if required.
        Repeated calls to this function will return the same signal object.
        """
        return name in self
